package mbp.agents;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import mbp.agents.AMbpAgentMap.ProcessMassage;
import mbp.base.MessageType;
import mbp.base.ServiceType;
import mbp.core.ServiceTypeBuilder;
import mbp.message.Message;
import mbp.message.server;

import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.lang.acl.ACLMessage;

/**
 * Agent rejesttr uslug. przechwuje i udostepnia nazwe serwera oraz typ uslugi jaki oferuje
 * @author Wojciech Wilanski
 *
 */
public class MbpRegisterAgent extends Agent
{
	//pamiec wpisy w rejestrze
	public Map<String, ServerInfo> serviceServerList;
	
	private Logger logger = Logger.getLogger(this.getClass());
	
	@Override
	protected void setup()
	{
		serviceServerList = new HashMap<String, ServerInfo>();
		
		ProcessMassage processMessage = new ProcessMassage();
		addBehaviour(processMessage);
		
		logger.info("Agent " + getAID().getName() + " is ready.");
	}
	
	/**
	 * Klasa przeznaczona do przechowwywania informacji o serwerze uslug
	 * @author Wojciech Wilanski
	 *
	 */
	public class ServerInfo
	{
		public String serviceType;
		public List<String> resourceType;
		
		public ServerInfo()
		{
			resourceType = new ArrayList<String>();
		}
	}
	
	private void processMessage(mbp.message.Message iMsg, String senderName)
	{
		MessageType messageType = iMsg.getMessageType();
		switch(messageType)
		{
		case REGISTER:
			onRegister(iMsg, senderName);
			break;
		case DEREGISTER:
			onDeRegister(iMsg, senderName);
			break;
		case SERVERLGET:
			onServerLGet(iMsg, senderName);
			break;
		default:
			logger.error("Message type: " + messageType + " not supported");
			break;		
		}	
	}
	
	/**
	 * Rejestracja serwera i nazy oferowanej przez niego uslugi
	 * @param iMsg
	 * @param senderName
	 */
	public void onRegister(mbp.message.Message iMsg, String senderName)
	{
		//nazwa serwera uslug
		String serverName = iMsg.getContentXml().servers.get(0).name;
		
		//informacje o usludze: typ uslugi, produkowane typy zasobow
		ServerInfo si = new ServerInfo();
		si.serviceType = iMsg.getContentXml().servers.get(0).type;
		
		//W wiadomosci powinien byc umieszczony obiekt extra. pierwsza wartosc to typ uslugi
		//kolejne to typy produkowanych zasobow 
		for(int i = 0; i<iMsg.getContentXml().extras.size(); i++)
		{		
			si.resourceType.add(iMsg.getContentXml().extras.get(i).value);
		}
		
		serviceServerList.put(serverName, si);
		logger.info("Registed new service server. Name: " + serverName + ", Service:" + si.serviceType);
	}
	
	/**
	 * Wyrejestrowanie serwera
	 * @param iMsg
	 * @param senderName
	 */
	public void onDeRegister(mbp.message.Message iMsg, String senderName)
	{
		String server = iMsg.getContentXml().servers.get(0).name;
		if(serviceServerList.containsKey(server))
		{
			serviceServerList.remove(server);
			logger.info("Removed service server from registry. Name: " + server);
		}
		else
		{
			logger.warn("Can not remove service server. The server name: " + server + " is not i the registry");
		}
	}
	
	/**
	 * Obsluga zadania przeslania lisy serwerow: Zapytac mozna o typ uslugi albo typ zasobu
	 * @param iMsg
	 * @param senderName
	 */
	public void onServerLGet(mbp.message.Message iMsg, String senderName)
	{
		//ustalenie jakie przyszlo zapytanie: typ uslugi / typ zasobu
		String requestKind = iMsg.getContentXml().extras.get(0).name;
		logger.debug("requestKind: " + requestKind);
		
		//Pobranie nazwy typu
		String objectType = iMsg.getContentXml().extras.get(0).value;
		
		logger.debug("Recieved request for: " + requestKind + " type: " + objectType + " from: " + senderName);
		
		List<server> serverList = new ArrayList<server>();
		
		if(requestKind.compareTo("service") == 0)
		{
			Iterator<String> it = serviceServerList.keySet().iterator();
			while(it.hasNext())
			{
				String s = it.next();
				if(serviceServerList.get(s).serviceType.compareTo(objectType) == 0)
				{
					server srv = new server();
					srv.name = s;
					srv.type = serviceServerList.get(s).serviceType;
					serverList.add(srv);
				}
			}
		}
		
		if(requestKind.compareTo("resource") == 0)
		{
			Iterator<String> it = serviceServerList.keySet().iterator();
			while(it.hasNext())
			{
				String s = it.next();
				if(serviceServerList.get(s).resourceType.get(0).compareTo(objectType) == 0)
				{
					server srv = new server();
					srv.name = s;
					srv.type = serviceServerList.get(s).serviceType;
					serverList.add(srv);
				}
			}
		}
		
		
		//wyslanie listy serwerow
		Message message = new Message(MessageType.SERVERL, getLocalName(), senderName);
		message.getContentXml().servers = serverList;
		send(message.GetACLMessage());
		
		logger.debug("Sent reply to: " + senderName + ". Found the number of servers: " + serverList.size()); 
	}
	
	public class ProcessMassage extends CyclicBehaviour
	{

		@Override
		public void action() 
		{
			ACLMessage msg = myAgent.receive();
			
			if(msg != null)
			{
				logger.debug(msg.toString());
				mbp.message.Message iMsg = new mbp.message.Message(msg);
				if(iMsg.isValid())
				{
					//logger.info("Message is valid - type: " + iMsg.getMessageType());
					processMessage(iMsg, msg.getSender().getLocalName());
				}
				else
				{
					logger.error("Message in not valid!");
				}
			}
			else
			{
				block();
			}
		}

	}

}
